/*
 * Created on 2008-7-4
 *
 * TODO
 */
package jacky.lanlan.song.util.sp;

import java.lang.reflect.Array;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 开关转换器，每次开关都会在设定的两个值之间转换。
 * <p>
 * <i>开关的初始状态为“关”状态。</i>
 * <p >
 * <b>线程安全。</b>
 * @author Jacky.Song
 */
public class Switch<T> {

	private AtomicBoolean state=new AtomicBoolean();
	private T on;
	private T off;
	
	/**
	 * 设置开关的2个值。
	 * @param on 当开关处于开状态时的值。
	 * @param off 当开关处于关状态时的值。
	 */
	public Switch(T on,T off) {
		this.on=on;
		this.off=off;
	}

	/**
	 * 切换开关状态，并返回切换前开关的值。
   * @return 切换前的开关状态值。
   */
	public T turn() {
		return state.getAndSet(!state.get())?on:off;
	}
	
	/**
	 * 打开开关。
	 */
	public void on() {
		state.set(true);
	}
	
	/**
	 * 关闭开关。
	 */
	public void off() {
		state.set(false);
	}
	
	/**
	 * 查询开关的当前状态。
	 * @return true如果为开，false如果为关
	 */
	public boolean state() {
		return state.get();
	}
	
	/**
	 * 得到开关的当前值。
	 * @return 开关的当前值。
	 */
	public T value() {
		return state()?on:off;
	}
	
	/**
	 * 生成一个指定长度的数组，数组元素按照on-off-on...的顺序排列。
	 * @param length 数组长度
	 * @return 生成好的数组
	 */
	public T[] generateArray(int length) {
		Object [] temp=new Object[length];
		//锁定state，数组创建完以后才能修改状态
		synchronized (state) {
			on();//切换到on状态
			for (int i = 0; i < length; i++) {
				temp[i]=turn();
			}
		}
		T [] array=(T[]) Array.newInstance(temp[0].getClass(),length);
		System.arraycopy(temp, 0, array, 0, length);
		return array;
	}
	
}